package com.bsoft.aop.logAspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

import cn.hutool.core.codec.Base64;

/**
 * 请求日志
 */
@Slf4j
@Aspect
//@Component
public class WebLogAspect {

    private ThreadLocal<Long> startTime = new ThreadLocal<Long>();

    private String className = "";
    private String methodName = "";
    private String params = "";
    private String url = "";
    private String ip = "";

    //定义的切点就是针对那些方法有些 (这里是public * com.bsoft.bswhis.controller路径下的所有的)
//    @Pointcut("execution(public * com.bsoft.bswhis.bsxml.controller.*.*(..))")
    @Pointcut("execution(* com.bsoft.service.EntranceWebService.*(..))")
    public void webLog() {

    }

    /*//环绕通知(@Around)来解密方法的参数。 顺序1
    @Around(value = "webLog()")
    public Object doBeforeAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            if (args[i] instanceof String) {
                args[i] = new String(Base64.decodeStr(arg.toString()));
            }
        }
        return joinPoint.proceed(args); // 继续执行方法，但用解密后的参数
    }*/


    //通过JoinPoint可以获取被代理方法的各种信息  顺序2
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        startTime.set(System.currentTimeMillis());
//        className = joinPoint.getTarget().getClass().getName();
//
//        // 获取请求对象
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = attributes.getRequest();

     /*   // 请求执行前，记录请求内容
        log.info("请求URL : " + request.getRequestURL().toString());
        log.info("请求HTTP_METHOD : " + request.getMethod());
        log.info("请求IP : " + request.getRemoteAddr());
        log.info("请求CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("请求参数值PARAMS : " + Arrays.toString(joinPoint.getArgs()));*/
    }

    //环绕通知(@Around)来解密方法的参数。 顺序1
    @Around(value = "webLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            if (args[i] instanceof String) {
                args[i] = new String(Base64.decodeStr(arg.toString()));
            }
        }

        Object result  = joinPoint.proceed(args);
        if (result !=null){
            result = Base64.encode(result.toString());
        }
        return result ;
    }

    //若目标方法无异常，执行@AfterReturning注解方法的业务逻辑  顺序3
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(JoinPoint joinPoint,Object ret) throws IOException {
        log.info("响应时间SPEND_TIME : " + (System.currentTimeMillis() - startTime.get()));
    }

    //若目标方法有异常，执行AfterThrowing注解方法的业务逻辑  顺序3
    @AfterThrowing(value = "webLog()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        log.error("异常信息:请求URL {}:请求方法名 {} 异常:{}", request.getRequestURL().toString(),request.getMethod(), e.getMessage());
    }
}
